/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/

/**
 * @brief Internal interface for IR-codes generation.
 *
 * @author  WXQ#XDU
 * @date    2025.01
 */

#pragma once

#ifndef AMCC__EMIT_INNER_H
#define AMCC__EMIT_INNER_H

#include <string.h>

#include "../../include/amcc_log.h"
#include "../../include/amcc_error.h"
#include "../../include/amcc_stack.h"
#include "../../include/ircode.h"

#include "tempmgr.h"
#include "codemgr.h"
#include "backpatch.h"
#include "comment.h"

AMCC_DECL_BEGIN



// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// To support nested function definitions, emitter should record
//   the nesting path in a stack.
// In order of inside-out in source program (top-down in stack),
// this path starts from the current function,
//   then its direct enclosing function, then indirect enclosing function, ...,
//   and finally, the translation unit.
// Here, the translation unit is treated as a virtual, unnamed,
//       biggest function.
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


/**
 * Type of elements of function-stack .
 *
 * Each instance of this type is corresponding to a function,
 * and is stored in emitter.functionStack.
 */
typedef struct emitter_funcinfo {

    // The next temporary variable id in current function.
    t_tempvar_id    nextTempVarNumber;    // Starting from 1

    // the next three-address-code id,
    // just the variable "nextstat" in textbook
    t_ircode_id     nextCodeId;            // Starting from 1

    // tree root of a function definition(marked by funcDeclaration),
    // or the translation unit (marked by translationUnit)
    t_tree_ptr      funcDeclNode;

    // IR-codes of the current function, excluding nested functions.
    // The underlying type is  list<t_ircode_ptr>
    t_list_ptr      ircodes;

    // Collection of (labelName, target_instruction_id) pairs
    // for all labels in current function.
    //
    // Elements key is "labelName",  "target_instruction_id" is the
    // first IR-code id defined by "labelName".
    //
    // when emitter meets a label definition, a new element is
    // put to this map, and, emitter performs back-patching all
    // forward reference to this label.
    //
    t_hashmap_ptr  targetOfLabels;

    // Collection of  (labelName, list<goto_instruction>) pairs
    // for all labels in current function.
    //
    // Elements key is "labelName",  the list is the chain with zero
    // or more goto-instructions.
    //
    // When emitter meets the first forward reference to a label,
    //   a new map element is put to this map, and
    // when emitter meets other forward references to same label again,
    //   no map element is created, but just append a 'goto_?_' to
    //   the chain of this label.
    //
    t_hashmap_ptr  chainOfLabels;

} t_emitter_funcinfo;



/**
 * Class emitter that perform IR-code generation.
 */
struct ircode_emitter {
    t_tree_listener base ;   // instance of base class

// input data of emitter

    t_tree_ptr      treeRootPtr;     // root of parse tree
    t_symtable_ptr  symtableRootPtr; // root of symbol table tree

// inner working data

    int  nErrors; // counter for errors during code generation

    // The nesting path from current function to the translation unit.
    // Each element is an instance of t_emitter_funcinfo.
    t_stack            functionStack;
    t_emitter_funcinfo * currFuncInfo; // element on stack top

    t_tempmgr_ptr      tempmgrPtr; // manager for temporary variables
    t_backpatcher_ptr  backpatcherPtr;
    t_ircodemgr_ptr    ircodemgrPtr;
};



/**
 * @brief  Prepare to analyze a function.
 *
 * This function is called when emitter enters into a function definition.
 *
 * @param pThis          pointer to this emitter
 * @param funcDeclNode   tree root of a function definition
 *                       (marked by funcDeclaration or translationUnit)
 */
extern void emitter_entry_func(t_emitter_ptr pThis, t_tree_ptr funcDeclNode);

/**
 * @brief  Finish analyzing a function.
 *
 * This function is called when emitter exits from a function definition.
 *
 * @param pThis      pointer to this emitter
 */
extern void emitter_exit_func(t_emitter_ptr pThis);


// Pass attributes of the specified child to this node
//
t_codeattr_ptr emit_passAttributeOfChild__( t_tree_ptr node, int idxChild );


// Get the arithmetic value(address) of an expression.
// For boolean-expr, emits some codes and return a temporary
//    variable(address) which is 1(true) or 0(false).
// For arithmetic-expr,
//   if expr is scalar, just returns its value(address);
//   if expr is array element, emits some codes and returns
//   a temporary variable(address) which is its value(address).
//
extern t_ir_address_ptr emit_getExprAddress__(t_codemgr_ptr codemgr, t_codeattr_ptr E_attr);

// Convert an arithmetic expr to boolean expr.
// This function will emit code like:
//   (k)    if E.place goto -  ==>> .tc = make-chain
//   (k+1)  goto -             ==>> .fc = make-chain
// and return  k.
//
extern t_ircode_id  emit_convertExprToBool__ (t_codemgr_ptr  codemgr,
                                    t_codeattr_ptr operandAttr, t_codeattr_ptr resultAttr);




// -----------------------------------------------------------------------
// Semantic actions for all interesting parse tree nodes(productions)
//


#define EMIT_TREEFUNC(fn)  void fn(t_tree_listener_ptr, t_tree_ptr)

// semantic actions for all declarations

extern EMIT_TREEFUNC(emit_enter_translationUnit);
extern EMIT_TREEFUNC(emit_exit_translationUnit);
extern EMIT_TREEFUNC(emit_enter_functionDeclaration);
extern EMIT_TREEFUNC(emit_exit_functionDeclaration);
extern EMIT_TREEFUNC(emit_exit_parameterList);
extern EMIT_TREEFUNC(emit_exit_initDeclarator);

// semantic actions for all expressions

extern EMIT_TREEFUNC(emit_exit_expression);
extern EMIT_TREEFUNC(emit_exit_assignmentExpr);
extern EMIT_TREEFUNC(emit_exit_logicalOrExpr);
extern EMIT_TREEFUNC(emit_exit_logicalAndExpr);
extern EMIT_TREEFUNC(emit_exit_equalityExpr);
extern EMIT_TREEFUNC(emit_exit_relationalExpr);
extern EMIT_TREEFUNC(emit_exit_additiveExpr);
extern EMIT_TREEFUNC(emit_exit_multiplicativeExpr);
extern EMIT_TREEFUNC(emit_exit_unaryExpr);
extern EMIT_TREEFUNC(emit_exit_primaryExpr);
extern EMIT_TREEFUNC(emit_exit_leftValue);
extern EMIT_TREEFUNC(emit_exit_functionCall);
extern EMIT_TREEFUNC(emit_exit_argumentList);

extern EMIT_TREEFUNC(emit_visit_terminal);

// semantic actions for all statements

extern EMIT_TREEFUNC(emit_enter_statement);
extern EMIT_TREEFUNC(emit_exit_statement);
extern EMIT_TREEFUNC(emit_exit_selectionStmt);
extern EMIT_TREEFUNC(emit_exit_iterationStmt);
extern EMIT_TREEFUNC(emit_exit_jumpStmt);
extern EMIT_TREEFUNC(emit_exit_expressionStmt);
extern EMIT_TREEFUNC(emit_enter_labeledStmt);
extern EMIT_TREEFUNC(emit_exit_labeledStmt);
extern EMIT_TREEFUNC(emit_enter_compoundStmt);
extern EMIT_TREEFUNC(emit_exit_compoundStmt);
extern EMIT_TREEFUNC(emit_enter_blockItemStmt);
extern EMIT_TREEFUNC(emit_exit_blockItemStmt);



AMCC_DECL_END

#endif //AMCC__EMIT_INNER_H
